#include <QTest>
#include "MarketEngine.h"
#include <QSignalSpy>
#include <QEventLoop>
#include <QTimer>
#include <QDir>

using namespace MarketEngine;

class TestMarketEngine : public QObject {
    Q_OBJECT

private slots:
    void initTestCase() {
        // 创建日志目录
        QDir().mkpath("logs/market_test");
        QDir().mkpath("flow");
        
        // 创建测试用的 logger
        auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
        auto file_sink = std::make_shared<spdlog::sinks::daily_file_sink_mt>(
            "logs/market_test/test.log", 0, 0);

        testLogger = std::make_shared<spdlog::logger>(
            "market_test", 
            spdlog::sinks_init_list{console_sink, file_sink}
        );
        
        testLogger->set_level(spdlog::level::debug);
        testLogger->set_pattern("[%Y-%m-%d %H:%M:%S.%e][%n][%^%l%$] %v");
    }

    void cleanupTestCase() {
        testLogger->info("Finished MarketEngine tests");
    }

    // 测试初始化配置
    void testInitialization() {
        testLogger->info("TestMarketEngine::testInitialization() entering");
        
        Engine engine;
        MarketConfig config;
        
        // 测试1：故意使用空配置，期望初始化失败
        testLogger->info("Testing initialization with empty config (expected to fail)");
        QVERIFY(!engine.init(config, testLogger));
        
        // 测试2：使用有效配置，期望初始化成功
        testLogger->info("Testing initialization with valid config");
        config = getTestConfig();
        QVERIFY(engine.init(config, testLogger));
        QCOMPARE(engine.connectionStatus(), ConnectionStatus::Disconnected);
    }

    // 测试连接和断开
    void testConnection() {
        testLogger->info("TestMarketEngine::testConnection() entering");
        {  // 使用作用域来确保资源正确释放
            Engine engine;
            MarketConfig config = getTestConfig();
            
            QSignalSpy statusSpy(&engine, &Engine::onStatusChanged);
            QVERIFY(engine.init(config, testLogger));
            
            engine.start();
            
            QVERIFY(waitForStatus(engine, ConnectionStatus::Connected, 30000));
            QCOMPARE(engine.connectionStatus(), ConnectionStatus::Connected);
            
            engine.stop();
            
            QVERIFY(waitForStatus(engine, ConnectionStatus::Disconnected, 30000));
            QCOMPARE(engine.connectionStatus(), ConnectionStatus::Disconnected);
        }  // engine 在这里被销毁
        testLogger->info("TestMarketEngine::testConnection() exiting");
    }

    // 测试订阅和取消订阅
    void testSubscription() {
        testLogger->info("TestMarketEngine::testSubscription() entering");
        {  // 使用作用域来确保资源正确释放
            Engine engine;
            MarketConfig config = getTestConfig();
            
            // 连接行情数据信号，用于打印行情
            connect(&engine, &Engine::onTick, 
                [this](const CThostFtdcDepthMarketDataField& tick) {
                    testLogger->info("Tick data - Symbol: {}, Last Price: {}, Volume: {}, Bid: {}, Ask: {}, Time: {}, OpenInterest: {}, Turnover: {}",
                        tick.InstrumentID,
                        tick.LastPrice,
                        tick.Volume,
                        tick.BidPrice1,
                        tick.AskPrice1,
                        tick.UpdateTime,
                        tick.OpenInterest,
                        tick.Turnover
                    );
                });
            
            QSignalSpy tickSpy(&engine, &Engine::onTick);
            QSignalSpy errorSpy(&engine, &Engine::onError);
            
            QVERIFY(engine.init(config, testLogger));
            engine.start();
            
            QVERIFY(waitForStatus(engine, ConnectionStatus::Connected, 30000));
            QCOMPARE(engine.connectionStatus(), ConnectionStatus::Connected);
            
            std::vector<QString> symbols = {"SA505", "ni2505", "jm2505"};
            QVERIFY(engine.subscribe(symbols));
            
            // 等待并接收更多的tick数据
            const int expectedTicks = 50;  // 期望收到50个tick
            const int waitTimePerTick = 60000;  // 每个tick最多等待60秒
            
            testLogger->info("Waiting for {} ticks, {} seconds per tick...", expectedTicks, waitTimePerTick/1000);
            
            for(int i = 0; i < expectedTicks; i++) {
                if(!tickSpy.wait(waitTimePerTick)) {
                    testLogger->info("No more ticks received after {} ticks, stopping collection", tickSpy.count());
                    break;
                }
                
                // 每收到10个tick打印一次进度
                if((i + 1) % 10 == 0) {
                    testLogger->info("Received {} ticks so far...", i + 1);
                }
            }
            
            testLogger->info("Received {} ticks in total", tickSpy.count());
            QVERIFY(tickSpy.count() > 0);
            QVERIFY(errorSpy.isEmpty());
            
            QVERIFY(engine.unsubscribe(symbols));
            
            engine.stop();
            QVERIFY(waitForStatus(engine, ConnectionStatus::Disconnected, 30000));
        }  // engine 在这里被销毁
        testLogger->info("TestMarketEngine::testSubscription() exiting");
    }

    // 测试错误处理
    void testErrorHandling() {
        testLogger->info("TestMarketEngine::testErrorHandling() entering");
        {  // 使用作用域来确保资源正确释放
            Engine engine;
            MarketConfig config = getTestConfig();
            
            QSignalSpy errorSpy(&engine, &Engine::onError);
            QVERIFY(engine.init(config, testLogger));
            
            engine.start();
            
            QVERIFY(waitForStatus(engine, ConnectionStatus::Connected, 30000));
            QCOMPARE(engine.connectionStatus(), ConnectionStatus::Connected);
            
            std::vector<QString> invalidSymbols = {"INVALID_SYMBOL"};
            QVERIFY(engine.subscribe(invalidSymbols));
            
            QVERIFY(errorSpy.wait(5000));
            QVERIFY(!errorSpy.isEmpty());
            
            engine.stop();
            QVERIFY(waitForStatus(engine, ConnectionStatus::Disconnected, 30000));
        }  // engine 在这里被销毁
        testLogger->info("TestMarketEngine::testErrorHandling() exiting");
    }

    // 测试重连和清理
    void testReconnection() {
        testLogger->info("TestMarketEngine::testReconnection() entering");
        {
            Engine engine;
            MarketConfig config = getTestConfig();
            QSignalSpy statusSpy(&engine, &Engine::onStatusChanged);
            
            // 第一次连接
            testLogger->info("First connection attempt");
            QVERIFY(engine.init(config, testLogger));
            engine.start();
            
            // 等待连接成功
            QVERIFY(waitForStatus(engine, ConnectionStatus::Connected, 30000));
            QTest::qWait(1000);  // 等待登录完成
            
            // 订阅一些合约
            std::vector<QString> symbols = {"SA505", "ni2505"};
            QSignalSpy tickSpy(&engine, &Engine::onTick);
            QVERIFY(engine.subscribe(symbols));
            
            // 等待接收到行情数据
            testLogger->info("Waiting for market data...");
            QVERIFY(tickSpy.wait(5000));
            
            // 停止连接
            testLogger->info("Stopping connection");
            engine.stop();
            QVERIFY(waitForStatus(engine, ConnectionStatus::Disconnected, 30000));
            
            // 等待一段时间
            QTest::qWait(2000);
            
            // 重新初始化并连接
            testLogger->info("Attempting reconnection");
            QVERIFY(engine.init(config, testLogger));
            engine.start();
            
            // 等待重新连接成功
            QVERIFY(waitForStatus(engine, ConnectionStatus::Connected, 30000));
            QTest::qWait(1000);  // 等待登录完成
            
            // 验证重新订阅是否成功
            tickSpy.clear();
            QVERIFY(engine.subscribe(symbols));
            
            // 等待接收到行情数据
            testLogger->info("Waiting for market data after reconnection...");
            QVERIFY(tickSpy.wait(5000));
            
            // 最终清理
            testLogger->info("Final cleanup");
            QVERIFY(engine.unsubscribe(symbols));
            engine.stop();
            QVERIFY(waitForStatus(engine, ConnectionStatus::Disconnected, 30000));
            
            // 验证状态变化
            QList<ConnectionStatus> expectedStates;
            for (int i = 0; i < statusSpy.count(); ++i) {
                auto status = statusSpy.at(i).at(0).value<ConnectionStatus>();
                expectedStates.append(status);
                testLogger->info("Status change {}: {}", i, static_cast<int>(status));
            }
            
            // 验证状态变化是否符合预期
            QVERIFY(expectedStates.contains(ConnectionStatus::Connected));
            QVERIFY(expectedStates.contains(ConnectionStatus::Disconnected));
        }
        testLogger->info("TestMarketEngine::testReconnection() exiting");
    }

private:
    std::shared_ptr<spdlog::logger> testLogger;
    
    // 辅助函数：获取测试配置
    MarketConfig getTestConfig() {
        MarketConfig config;
        config.brokerID = "9999";
        config.userID = "8641";
        config.password = "123456";
        config.frontAddress = "tcp://121.37.80.177:20004";
        config.mdDllPath = "../include/CTP/thostmduserapi_tts.so";
        config.flowPath = "flow/";
        config.symbols = {"SA505", "ni2505", "jm2505"};  // 使用主力合约
        return config;
    }

    // 辅助函数：等待指定状态
    bool waitForStatus(Engine& engine, ConnectionStatus expectedStatus, int timeout = 30000) {
        if (engine.connectionStatus() == expectedStatus) {
            return true;
        }
        
        QEventLoop loop;
        QTimer::singleShot(timeout, &loop, &QEventLoop::quit);
        
        // 使用 QMetaObject::Connection 来存储连接，以便后续断开
        QMetaObject::Connection conn = connect(&engine, &Engine::onStatusChanged,
            [&](ConnectionStatus status) {
                if (status == expectedStatus) {
                    loop.quit();
                }
            });
        
        loop.exec();
        
        // 断开连接
        disconnect(conn);
        
        return engine.connectionStatus() == expectedStatus;
    }
};

QTEST_MAIN(TestMarketEngine)
#include "TestMarketEngine.moc" 